home *** CD-ROM | disk | FTP | other *** search
/ ftp.mactech.com 2010 / ftp.mactech.com.tar / ftp.mactech.com / macintosh-c / macc-carbon-demos-nonbinhex.sit / macc-carbon-demos-nonbinhex / chap18-demo-carbon events / Files.c < prev    next >
C/C++ Source or Header  |  2001-06-11  |  20KB  |  727 lines

  1. // *******************************************************************************************
  2. // Files.c
  3. // *******************************************************************************************
  4.  
  5. // ………………………………………………………………………………………………………………………………………………………………………………………………………………………… includes
  6.  
  7. #include "Files.h"
  8.  
  9. // …………………………………………………………………………………………………………………………………………………………………………………………………… global variables
  10.  
  11. Boolean            gRunningOnX = false;
  12. SInt16            gAppResFileRefNum;
  13. NavEventUPP    gGetFilePutFileEventFunctionUPP ;
  14. Boolean            gQuittingApplication = false;
  15.  
  16. extern SInt16    gCurrentNumberOfWindows;
  17. extern Rect        gDestRect,gViewRect;
  18.  
  19. // ************************************************************************************** main
  20.  
  21. void  main(void)
  22. {
  23.     MenuBarHandle    menubarHdl;
  24.     SInt32                response;
  25.     MenuRef                menuRef;
  26.     EventTypeSpec    applicationEvents[] =    { { kEventClassApplication, kEventAppActivated    },
  27.                                                                                 { kEventClassCommand,     kEventProcessCommand  },
  28.                                                                                 { kEventClassMenu,        kEventMenuEnableItems } };
  29.     EventLoopTimerRef timerRef;
  30.  
  31.     // ……………………………………………………………………………………………………………………………………………………………………………………………… do preliminaries
  32.  
  33.     doPreliminaries();
  34.  
  35.     // ………………………………………………………………………………………… save application's resource file file reference number
  36.  
  37.     gAppResFileRefNum = CurResFile();
  38.  
  39.     // ……………………………………………………………………………………………………………………………………………………………………… set up menu bar and menus
  40.     
  41.     menubarHdl = GetNewMBar(rMenubar);
  42.     if(menubarHdl == NULL)
  43.         doErrorAlert(MemError());
  44.     SetMenuBar(menubarHdl);
  45.     DrawMenuBar();
  46.  
  47.     Gestalt(gestaltMenuMgrAttr,&response);
  48.     if(response & gestaltMenuMgrAquaLayoutMask)
  49.     {
  50.         menuRef = GetMenuRef(mFile);
  51.         if(menuRef != NULL)
  52.         {
  53.             DeleteMenuItem(menuRef,iQuit);
  54.             DeleteMenuItem(menuRef,iQuit - 1);
  55.         }
  56.  
  57.         gRunningOnX = true;
  58.     }
  59.     else
  60.     {
  61.         menuRef = GetMenuRef(mFile);
  62.         if(menuRef != NULL)
  63.             SetMenuItemCommandID(menuRef,iQuit,kHICommandQuit);
  64.     }
  65.  
  66.     // ……………………………………………………………………………………………………………………………………… install required Apple event handlers
  67.  
  68.     doInstallAEHandlers();
  69.  
  70.     // ………………………………………………………………………………………………………………………………………………… install application event handler
  71.   
  72.     InstallApplicationEventHandler(NewEventHandlerUPP((EventHandlerProcPtr) appEventHandler),
  73.                                                                  GetEventTypeCount(applicationEvents),applicationEvents,
  74.                                                                  0,NULL);
  75.  
  76.     // ………………………………………………………………………………………………………………………… install a timer (for file synchronisation)
  77.  
  78.     InstallEventLoopTimer(GetCurrentEventLoop(),0,TicksToEventTime(15),
  79.                                                 NewEventLoopTimerUPP((EventLoopTimerProcPtr) doIdle),NULL,
  80.                                                 &timerRef);
  81.  
  82.     // …………… get universal procedure pointer to main Navigation Services services event function
  83.  
  84.     gGetFilePutFileEventFunctionUPP  = 
  85.                                                                 NewNavEventUPP((NavEventProcPtr) getFilePutFileEventFunction);
  86.  
  87.     // …………………………………………………………………………………………………………………………………………………………………… run application event loop
  88.  
  89.     RunApplicationEventLoop();
  90. }
  91.  
  92. // *************************************************************************** doPreliminaries
  93.  
  94. void  doPreliminaries(void)
  95. {
  96.     MoreMasterPointers(448);
  97.     InitCursor();
  98. }
  99.  
  100. // *********************************************************************** doInstallAEHandlers
  101.  
  102. void  doInstallAEHandlers(void)
  103. {
  104.     OSErr    osError;
  105.  
  106.     osError = AEInstallEventHandler(kCoreEventClass,kAEOpenApplication,
  107.                                     NewAEEventHandlerUPP((AEEventHandlerProcPtr) openAppEventHandler),
  108.                                     0L,false);
  109.     if(osError != noErr)    doErrorAlert(eInstallHandler);
  110.  
  111.     osError = AEInstallEventHandler(kCoreEventClass,kAEReopenApplication,
  112.                                     NewAEEventHandlerUPP((AEEventHandlerProcPtr) reopenAppEventHandler),
  113.                                     0L,false);
  114.     if(osError != noErr)    doErrorAlert(eInstallHandler);
  115.  
  116.     osError = AEInstallEventHandler(kCoreEventClass,kAEOpenDocuments,
  117.                                     NewAEEventHandlerUPP((AEEventHandlerProcPtr) openAndPrintDocsEventHandler),
  118.                                     kOpen,false);
  119.     if(osError != noErr)    doErrorAlert(eInstallHandler);
  120.  
  121.     osError = AEInstallEventHandler(kCoreEventClass,kAEPrintDocuments,
  122.                                     NewAEEventHandlerUPP((AEEventHandlerProcPtr) openAndPrintDocsEventHandler),
  123.                                     kPrint,false);
  124.     if(osError != noErr)    doErrorAlert(eInstallHandler);
  125.  
  126.     osError = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,
  127.                                     NewAEEventHandlerUPP((AEEventHandlerProcPtr) quitAppEventHandler),
  128.                                     0L,false);
  129.     if(osError != noErr)    doErrorAlert(eInstallHandler);
  130. }
  131.  
  132. // *************************************************************************** appEventHandler
  133.  
  134. OSStatus  appEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef,
  135.                                                     void * userData)
  136. {
  137.     OSStatus            result = eventNotHandledErr;
  138.     UInt32                eventClass;
  139.     UInt32                eventKind;
  140.     HICommand            hiCommand;
  141.     MenuID                menuID;
  142.     MenuItemIndex    menuItem;
  143.  
  144.     eventClass = GetEventClass(eventRef);
  145.     eventKind  = GetEventKind(eventRef);
  146.  
  147.     switch(eventClass)
  148.     {
  149.         case kEventClassApplication:
  150.             if(eventKind == kEventAppActivated)
  151.                 SetThemeCursor(kThemeArrowCursor);
  152.             break;
  153.  
  154.         case kEventClassCommand:
  155.             if(eventKind == kEventProcessCommand)
  156.             {
  157.                 GetEventParameter(eventRef,kEventParamDirectObject,typeHICommand,NULL,
  158.                                                     sizeof(HICommand),NULL,&hiCommand);
  159.                 menuID = GetMenuID(hiCommand.menu.menuRef);
  160.                 menuItem = hiCommand.menu.menuItemIndex;
  161.                 if((hiCommand.commandID != kHICommandQuit) && 
  162.                      (menuID >= mAppleApplication && menuID <= mDemonstration))
  163.                 {
  164.                     doMenuChoice(hiCommand.commandID);
  165.                     result = noErr;
  166.                 }
  167.             }
  168.             break;
  169.  
  170.         case kEventClassMenu:
  171.             if(eventKind == kEventMenuEnableItems)
  172.             {
  173.                 doAdjustMenus();
  174.                 result = noErr;
  175.             }
  176.             break;
  177.     }
  178.  
  179.     return result;
  180. }
  181.  
  182. // ************************************************************************ windowEventHandler
  183.  
  184. OSStatus  windowEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef,
  185.                                                          void* userData)
  186. {
  187.     OSStatus    result = eventNotHandledErr;
  188.     UInt32        eventClass;
  189.     UInt32        eventKind;
  190.     WindowRef    windowRef;
  191.  
  192.     eventClass = GetEventClass(eventRef);
  193.     eventKind  = GetEventKind(eventRef);
  194.  
  195.     switch(eventClass)
  196.     {
  197.         case kEventClassWindow:
  198.             GetEventParameter(eventRef,kEventParamDirectObject,typeWindowRef,NULL,sizeof(windowRef),
  199.                                                 NULL,&windowRef);
  200.             switch(eventKind)
  201.             {
  202.                 case kEventWindowDrawContent:
  203.                     doDrawContent(windowRef);
  204.                     result = noErr;
  205.                     break;
  206.  
  207.                 case kEventWindowClose:
  208.                     if(gQuittingApplication)
  209.                         doCloseCommand(kNavSaveChangesQuittingApplication);
  210.                     else
  211.                         doCloseCommand(kNavSaveChangesClosingDocument);
  212.                     result = noErr;
  213.                     break;
  214.             }
  215.             break;
  216.     }
  217.  
  218.     return result;
  219. }
  220.  
  221. // ************************************************************************************ doIdle
  222.  
  223. void  doIdle(void)
  224. {
  225.     if(GetWindowKind(FrontWindow()) == kApplicationWindowKind)
  226.         doSynchroniseFiles();
  227. }
  228.  
  229. // ********************************************************************************** doUpdate
  230.  
  231. void  doDrawContent(WindowRef windowRef)
  232. {
  233.     docStructureHandle    docStrucHdl;
  234.     GrafPtr                            oldPort;
  235.     Rect                                destRect;
  236.  
  237.     docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  238.  
  239.     GetPort(&oldPort);
  240.     SetPortWindowPort(windowRef);
  241.  
  242.     if((*docStrucHdl)->pictureHdl)
  243.     {
  244.         destRect = (*(*docStrucHdl)->pictureHdl)->picFrame;
  245.         OffsetRect(&destRect,170,54);
  246.         HLock((Handle) (*docStrucHdl)->pictureHdl);
  247.         DrawPicture((*docStrucHdl)->pictureHdl,&destRect);
  248.         HUnlock((Handle) (*docStrucHdl)->pictureHdl);
  249.     }
  250.     else if((*docStrucHdl)->editStrucHdl)
  251.     {
  252.         HLock((Handle) (*docStrucHdl)->editStrucHdl);
  253.         TEUpdate(&gDestRect,(*docStrucHdl)->editStrucHdl);
  254.         HUnlock((Handle) (*docStrucHdl)->editStrucHdl);
  255.     }
  256.  
  257.     if((*docStrucHdl)->windowTouched)
  258.     {
  259.         TextSize(48);
  260.         MoveTo(30,170);
  261.         DrawString("\pWINDOW TOUCHED");
  262.         TextSize(12);
  263.     }
  264.  
  265.     SetPort(oldPort);
  266. }
  267.  
  268. // ****************************************************************************** doMenuChoice
  269.  
  270. void  doMenuChoice(MenuCommand commandID)
  271. {
  272.     OSErr    osError = noErr;
  273.  
  274.     switch(commandID)
  275.     {
  276.         // ………………………………………………………………………………………………………………………………………………………………………… Apple/Application menu
  277.  
  278.         case Apple_About:
  279.             SysBeep(10);
  280.             break;
  281.  
  282.         // …………………………………………………………………………………………………………………………………………………………………………………………………………… File menu
  283.  
  284.         case File_New:
  285.             if(osError = doNewCommand())
  286.                 doErrorAlert(osError);
  287.             break;
  288.  
  289.         case File_Open:
  290.             if(osError = doOpenCommand() && osError == opWrErr)
  291.                 doErrorAlert(osError);
  292.             break;
  293.  
  294.         case File_Close:
  295.             if(osError = doCloseCommand(kNavSaveChangesClosingDocument))
  296.                 doErrorAlert(osError);
  297.             break;
  298.  
  299.         case File_Save:
  300.             if(osError = doSaveCommand())
  301.                 doErrorAlert(osError);
  302.             break;
  303.  
  304.         case File_SaveAs:
  305.             if(osError = doSaveAsCommand())
  306.                 doErrorAlert(osError);
  307.             break;
  308.  
  309.         case File_Revert:
  310.             if(osError = doRevertCommand())
  311.                 doErrorAlert(osError);
  312.             break;
  313.  
  314.         // …………………………………………………………………………………………………………………………………………………………………………………… Demonstration menu
  315.  
  316.         case Demo_TouchWindow:
  317.             doTouchWindow();
  318.             break;
  319.             
  320.         case Demo_ChooseAFolderDialog:
  321.             if(osError = doChooseAFolderDialog())
  322.                 doErrorAlert(osError);
  323.             break;
  324.     }
  325. }
  326.  
  327. // ***************************************************************************** doAdjustMenus
  328.  
  329. void  doAdjustMenus(void)
  330. {
  331.     OSErr                                osError;
  332.     MenuRef                            menuRef;
  333.     WindowRef                        windowRef;
  334.     docStructureHandle    docStrucHdl;
  335.  
  336.     if(gCurrentNumberOfWindows > 0)
  337.     {
  338.         if(gRunningOnX)
  339.         {
  340.             if((osError = GetSheetWindowParent(FrontWindow(),&windowRef)) == noErr)
  341.             {
  342.                 menuRef = GetMenuRef(mFile);
  343.                 DisableMenuCommand(menuRef,File_Close);
  344.                 DisableMenuCommand(menuRef,File_Save);
  345.                 DisableMenuCommand(menuRef,File_SaveAs);
  346.                 DisableMenuCommand(menuRef,File_Revert);
  347.                 menuRef = GetMenuRef(mDemonstration);
  348.                 DisableMenuCommand(menuRef,Demo_TouchWindow);
  349.                 return;
  350.             }
  351.             else
  352.                 windowRef = FrontWindow();
  353.         }
  354.         else
  355.             windowRef = FrontWindow();
  356.  
  357.         if(GetWindowKind(windowRef) == kApplicationWindowKind)
  358.         {
  359.             docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  360.  
  361.             menuRef = GetMenuRef(mFile);
  362.             EnableMenuCommand(menuRef,File_Close);
  363.             if((*docStrucHdl)->windowTouched)
  364.             {
  365.                 EnableMenuCommand(menuRef,File_Save);
  366.                 EnableMenuCommand(menuRef,File_Revert);
  367.             }
  368.             else
  369.             {
  370.                 DisableMenuCommand(menuRef,File_Save);
  371.                 DisableMenuCommand(menuRef,File_Revert);
  372.             }
  373.  
  374.             if(((*docStrucHdl)->pictureHdl != NULL) || 
  375.                  ((*(*docStrucHdl)->editStrucHdl)->teLength > 0))
  376.                 EnableMenuCommand(menuRef,File_SaveAs);
  377.             else
  378.                 DisableMenuCommand(menuRef,File_SaveAs);
  379.  
  380.             menuRef = GetMenuRef(mDemonstration);
  381.  
  382.             if(((*docStrucHdl)->pictureHdl != NULL) || 
  383.                  ((*(*docStrucHdl)->editStrucHdl)->teLength > 0))
  384.             {
  385.                 if((*docStrucHdl)->windowTouched == false)
  386.                     EnableMenuCommand(menuRef,Demo_TouchWindow);
  387.                 else
  388.                     DisableMenuCommand(menuRef,Demo_TouchWindow);
  389.             }
  390.             else
  391.                 DisableMenuCommand(menuRef,Demo_TouchWindow);
  392.         }
  393.     }
  394.     else
  395.     {
  396.         menuRef = GetMenuRef(mFile);
  397.         DisableMenuCommand(menuRef,File_Close);
  398.         DisableMenuCommand(menuRef,File_Save);
  399.         DisableMenuCommand(menuRef,File_SaveAs);
  400.         DisableMenuCommand(menuRef,File_Revert);
  401.         menuRef = GetMenuRef(mDemonstration);
  402.         DisableMenuCommand(menuRef,Demo_TouchWindow);
  403.     }
  404.  
  405.     DrawMenuBar();
  406. }
  407.  
  408. // ****************************************************************************** doErrorAlert
  409.  
  410. void  doErrorAlert(SInt16 errorCode)
  411. {
  412.     Str255    errorString, theString;
  413.     SInt16    itemHit;
  414.  
  415.     if(errorCode == eInstallHandler)
  416.         GetIndString(errorString,rErrorStrings,1);
  417.     else if(errorCode == eMaxWindows)
  418.         GetIndString(errorString,rErrorStrings,2);
  419.     else if(errorCode == eCantFindFinderProcess)
  420.         GetIndString(errorString,rErrorStrings,3);
  421.     else if(errorCode == opWrErr)
  422.         GetIndString(errorString,rErrorStrings,4);
  423.     else
  424.     {
  425.         GetIndString(errorString,rErrorStrings,5);
  426.         NumToString((SInt32) errorCode,theString);
  427.         doConcatPStrings(errorString,theString);
  428.     }
  429.  
  430.     if(errorCode != memFullErr)
  431.     {
  432.         StandardAlert(kAlertCautionAlert,errorString,NULL,NULL,&itemHit);
  433.     }
  434.     else
  435.     {
  436.         StandardAlert(kAlertStopAlert,errorString,NULL,NULL,&itemHit);
  437.         ExitToShell();
  438.     }
  439. }
  440.  
  441. // ***************************************************************************** doCopyPString
  442.  
  443. void  doCopyPString(Str255 sourceString,Str255 destinationString)
  444. {
  445.     SInt16    stringLength;
  446.  
  447.     stringLength = sourceString[0];
  448.     BlockMove(sourceString + 1,destinationString + 1,stringLength);
  449.     destinationString[0] = stringLength;
  450. }
  451.  
  452. // ************************************************************************** doConcatPStrings
  453.  
  454. void  doConcatPStrings(Str255 targetString,Str255 appendString)
  455. {
  456.     SInt16    appendLength;
  457.  
  458.     appendLength = MIN(appendString[0],255 - targetString[0]);
  459.  
  460.     if(appendLength > 0)
  461.     {
  462.         BlockMoveData(appendString+1,targetString+targetString[0]+1,(SInt32) appendLength);
  463.         targetString[0] += appendLength;
  464.     }
  465. }
  466.  
  467. // ***************************************************************************** doTouchWindow
  468.  
  469. void    doTouchWindow(void)
  470. {
  471.     WindowRef                        windowRef;
  472.     docStructureHandle    docStrucHdl;
  473.  
  474.     windowRef = FrontWindow();
  475.     docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  476.  
  477.     SetPortWindowPort(windowRef);
  478.  
  479.     TextSize(48);
  480.     MoveTo(30,170);
  481.     DrawString("\pWINDOW TOUCHED");
  482.     TextSize(12);
  483.  
  484.     (*docStrucHdl)->windowTouched = true;
  485.  
  486.     SetWindowModified(windowRef,true);                                                                                                         /////
  487. }
  488.  
  489. // *********************************************************************** openAppEventHandler
  490.  
  491. OSErr  openAppEventHandler(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefCon)
  492. {
  493.     OSErr    osError;
  494.  
  495.     osError = doHasGotRequiredParams(appEvent);
  496.     if(osError == noErr)
  497.         osError = doNewCommand();
  498.  
  499.     return osError;
  500. }
  501.  
  502. // ********************************************************************* reopenAppEventHandler
  503.  
  504. OSErr  reopenAppEventHandler(AppleEvent *appEvent,AppleEvent *reply,
  505.                                                              SInt32 handlerRefCon)
  506. {
  507.     OSErr    osError;
  508.  
  509.     osError = doHasGotRequiredParams(appEvent);
  510.     if(osError == noErr)
  511.         if(!FrontWindow())
  512.             osError = doNewCommand();
  513.  
  514.     return osError;
  515. }
  516.  
  517. // ************************************************************** openAndPrintDocsEventHandler
  518.  
  519. OSErr  openAndPrintDocsEventHandler(AppleEvent *appEvent,AppleEvent *reply,
  520.                                                                         SInt32 handlerRefcon)
  521. {
  522.     FSSpec            fileSpec;
  523.     AEDescList    docList;
  524.     OSErr                osError, ignoreErr;
  525.     SInt32            index, numberOfItems;
  526.     Size                actualSize;
  527.     AEKeyword        keyWord;
  528.     DescType        returnedType;
  529.     FInfo                fileInfo;
  530.  
  531.     osError = AEGetParamDesc(appEvent,keyDirectObject,typeAEList,&docList);
  532.  
  533.     if(osError == noErr)
  534.     {
  535.         osError = doHasGotRequiredParams(appEvent);
  536.         if(osError == noErr)
  537.         {
  538.             osError = AECountItems(&docList,&numberOfItems);
  539.             if(osError == noErr)
  540.             {
  541.                 for(index=1;index<=numberOfItems;index++)
  542.                 {
  543.                     osError = AEGetNthPtr(&docList,index,typeFSS,&keyWord,&returnedType,
  544.                                                                 &fileSpec,sizeof(fileSpec),&actualSize);
  545.                     if(osError == noErr)
  546.                     {
  547.                         osError = FSpGetFInfo(&fileSpec,&fileInfo);
  548.                         if(osError == noErr)
  549.                         {
  550.                             if(osError = doOpenFile(fileSpec,fileInfo.fdType))
  551.                                 doErrorAlert(osError);
  552.  
  553.                             if(osError == noErr && handlerRefcon == kPrint)
  554.                             {
  555.                                 // Call printing function here
  556.                             }
  557.                         }
  558.                     }
  559.                     else
  560.                         doErrorAlert(osError);
  561.                 }
  562.             }
  563.         }
  564.         else
  565.             doErrorAlert(osError);
  566.  
  567.         ignoreErr = AEDisposeDesc(&docList);
  568.     }
  569.     else
  570.         doErrorAlert(osError);
  571.  
  572.     return osError;
  573. }
  574.  
  575. // *********************************************************************** quitAppEventHandler
  576.  
  577. OSErr  quitAppEventHandler(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefcon)
  578. {
  579.     OSErr                                osError;
  580.     WindowRef                        windowRef, previousWindowRef;
  581.     docStructureHandle    docStrucHdl;
  582.     SInt16                            touchedWindowsCount = 0;
  583.     EventRef                        eventRef;
  584.     EventTargetRef            eventTargetRef;
  585.     SInt16                            itemHit;
  586.  
  587.     osError = doHasGotRequiredParams(appEvent);
  588.     if(osError == noErr)
  589.     {
  590.         if(FrontWindow())
  591.         {
  592.             // ……………… if any window has a sheet, bring to front, play system alert sound, and return
  593.  
  594.             windowRef = GetFrontWindowOfClass(kSheetWindowClass,true);
  595.             if(windowRef)
  596.             {
  597.                 SelectWindow(windowRef);
  598.                 SysBeep(10);
  599.                 return noErr;
  600.             }
  601.  
  602.             // ……………………………………………………………………………………………………………………………………………………………………… count touched windows
  603.  
  604.             windowRef = FrontWindow();
  605.             do
  606.             {
  607.                 docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  608.                 if((*docStrucHdl)->windowTouched == true)
  609.                     touchedWindowsCount++;
  610.                 previousWindowRef = windowRef;
  611.             } while(windowRef = GetNextWindowOfClass(previousWindowRef,kDocumentWindowClass,true));
  612.  
  613.             // …………………………………………………………………………………………………………………… if no touched windows, simply close down
  614.  
  615.             if(touchedWindowsCount == 0)
  616.                 QuitApplicationEventLoop();
  617.  
  618.             // ……………………………………………………………………………… if touched windows are present, and if running on OS X  
  619.  
  620.             if(gRunningOnX)
  621.             {
  622.  
  623.                 // …… if one touched window, cause Save Changes alert on that window, close all others
  624.  
  625.                 if(touchedWindowsCount == 1)
  626.                 {
  627.                     gQuittingApplication = true;
  628.                     CreateEvent(NULL,kEventClassWindow,kEventWindowClose,0,kEventAttributeNone,
  629.                                             &eventRef);
  630.                     eventTargetRef = GetWindowEventTarget(FrontWindow());
  631.                     SendEventToEventTarget(eventRef,eventTargetRef);
  632.                 }
  633.  
  634.             // …… if more than one touched window, create Review Changes alert, handle button clicks
  635.  
  636.             else if(touchedWindowsCount > 1)
  637.             {
  638.                 itemHit = doReviewChangesAlert(touchedWindowsCount);
  639.  
  640.                     if(itemHit == kAlertStdAlertOKButton)
  641.                     {
  642.                         gQuittingApplication = true;
  643.                         CreateEvent(NULL,kEventClassWindow,kEventWindowClose,0,kEventAttributeNone,
  644.                                                 &eventRef);
  645.                         eventTargetRef = GetWindowEventTarget(FrontWindow());
  646.                         SendEventToEventTarget(eventRef,eventTargetRef);
  647.                     }
  648.                     else if(itemHit == kAlertStdAlertCancelButton)
  649.                         gQuittingApplication = false;
  650.                     else if(itemHit == kAlertStdAlertOtherButton)
  651.                         QuitApplicationEventLoop();
  652.                 }
  653.             }
  654.  
  655.             // ………………………………………………………………………… if touched windows are present, and if running on OS 8/9
  656.  
  657.             else
  658.             {
  659.                 gQuittingApplication = true;
  660.                 CreateEvent(NULL,kEventClassWindow,kEventWindowClose,0,kEventAttributeNone,
  661.                                         &eventRef);
  662.                 eventTargetRef = GetWindowEventTarget(FrontWindow());
  663.                 SendEventToEventTarget(eventRef,eventTargetRef);
  664.             }
  665.         }
  666.         else
  667.             QuitApplicationEventLoop();
  668.     }
  669.  
  670.     return osError;
  671. }
  672.  
  673. // ******************************************************************** doHasGotRequiredParams
  674.  
  675. OSErr  doHasGotRequiredParams(AppleEvent *appEvent)
  676. {
  677.     DescType    returnedType;
  678.     Size            actualSize;
  679.     OSErr            osError;
  680.  
  681.     osError = AEGetAttributePtr(appEvent,keyMissedKeywordAttr,typeWildCard,&returnedType,
  682.                                                         NULL,0,&actualSize);
  683.     if(osError == errAEDescNotFound)
  684.         osError = noErr;
  685.     else if(osError == noErr)
  686.         osError = errAEParamMissed;
  687.  
  688.     return osError;
  689. }
  690.  
  691. // ********************************************************************** doReviewChangesAlert
  692.  
  693. SInt16  doReviewChangesAlert(SInt16 touchedWindowsCount)
  694. {
  695.     AlertStdCFStringAlertParamRec    paramRec;
  696.     Str255            messageText1 = "\pYou have ";
  697.     Str255            messageText2 = "\p Files documents with unsaved changes. ";
  698.     Str255            messageText3 = "\pDo you want to review these changes before quitting?";
  699.     Str255            countString;
  700.     CFStringRef    messageText;
  701.     CFStringRef    informativeText = 
  702.                             CFSTR("If you don't review your documents, all your changes will be lost.");
  703.     DialogRef                dialogRef;
  704.     DialogItemIndex    itemHit;
  705.  
  706.     NumToString(touchedWindowsCount,countString);
  707.     doConcatPStrings(messageText1,countString);    
  708.     doConcatPStrings(messageText1,messageText2);    
  709.     doConcatPStrings(messageText1,messageText3);    
  710.   messageText = CFStringCreateWithPascalString(NULL,messageText1,CFStringGetSystemEncoding());
  711.  
  712.     GetStandardAlertDefaultParams(¶mRec,kStdCFStringAlertVersionOne);
  713.     paramRec.movable            = true;
  714.     paramRec.defaultText    = CFSTR("Review Changes…");
  715.     paramRec.cancelText        = CFSTR("Cancel");
  716.     paramRec.otherText        = CFSTR("Discard Changes");
  717.  
  718.     CreateStandardAlert(kAlertStopAlert,messageText,informativeText,¶mRec,&dialogRef);
  719.     RunStandardAlert(dialogRef,NULL,&itemHit);
  720.  
  721.     if(messageText != NULL)
  722.         CFRelease(messageText);
  723.  
  724.     return itemHit;
  725. }
  726.  
  727. // *******************************************************************************************